home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 016 / 26time20.arc / 26TIME20.ASM < prev    next >
Encoding:
Assembly Source File  |  1986-12-03  |  18.6 KB  |  645 lines

  1. ;--------------------------------------------------------------------------
  2. ;-------------------------------  26TIME v1.0  ----------------------------
  3. ;--------------------------------------------------------------------------
  4. ;
  5. ;  PROGRAM   26TIME
  6. ;  VERSION   2.0
  7. ;  AUTHOR    PETER NELSON
  8. ;
  9. ;  DESCRIPTION:
  10. ;
  11. ;  This program works with the IBM CGA cards, IBM MONO cards, Hercules
  12. ;  cards, and Compaqs.  It resets the graphics chip to display 26 instead of
  13. ;  the normal 25 rows of text on the screen.  On the 26th line is
  14. ;  displayed the time, updated Once per minute.  It is theoretically
  15. ;  possible to use this program with a normal graphics card.  You would
  16. ;  have to put the time in the upper right corner, and check 18
  17. ;  times/second to see if it had scrolled off the screen yet.  If it
  18. ;  had, you would have to redisplay it.  This program checks
  19. ;  twice/second the the color of the lower-right character of the
  20. ;  screen.  It then prints the 26th row that color, and displays the
  21. ;  time using that color too.  This makes it look good no matter what
  22. ;  program you are running.  If the color of the lower-right character
  23. ;  changes, it redraws the entire bottom line, including the time. Every
  24. ;  time the time is displayed, there is a quiet "tick" sound made.  It
  25. ;  is possible to have the seconds being displayed as they change, or
  26. ;  have the colon flash once/second, but I decided this would eat up too
  27. ;  much processor power.
  28. ;
  29. ;  REVISIONS:
  30. ;
  31. ;  VERSION #    AUTHOR        DESCRIPTION
  32. ;
  33. ;        1.1    Peter Nelson    Some programs would blank the screen by
  34. ;                a hardware method that also ended up blanking
  35. ;                my time display.  Added a check to see if
  36. ;                the last position on the 26th line had an
  37. ;                'm'.  If not, I redisplayed.  This makes it
  38. ;                compatible with Lotus-123.
  39. ;    1.2    Peter Nelson    Fixed bug.  If it was 12:00 (noon or
  40. ;                midnight), the am/pm indicator would be
  41. ;                wrong.  Now is correct.
  42. ;    1.3    Peter Nelson    Prints time one space to the left of the
  43. ;                right edge of the lowest line now.
  44. ;    2.0    Peter Nelson    Now works with IBM Mono cards, Compaqs, and
  45. ;                Hercules cards.
  46. ;
  47. ;
  48. ;------------------------------  INCLUDES  --------------------------------
  49.  
  50. include    \asm\macros.asm        ; defines the IFR macro
  51. include    \asm\equates.asm    ; has many generally used values equated
  52.  
  53. ;------------------------------  EQUATES  ---------------------------------
  54. ;
  55. ; These are equates I would probably NEVER use in any other program.
  56.  
  57. COMPAQ_CO    EQU    'OC'      ; Value of 'CO'(ompaq) stored in mem
  58. COMPAQ_SEG    EQU    0F000h    ; Location of 'COMPAQ' if a compaq
  59. COMPAQ_OFF    EQU    0FFEAh    ; computer is being used.
  60.  
  61.  
  62. ;------------------------------  PUBLICS  ---------------------------------
  63. ;
  64. ; The public directive allows the use of these labels by the symbolic
  65. ; debugger (SYMDEB).
  66.  
  67.  
  68. public    start, begin, setvectors, int18_routine, int18_cont1, exit
  69. public    checkrow, check_cont0, check_cont1, checkrow_exit
  70. public    checkrow_exit_fine, checkrow_exit, showtime, show_cont1, show_cont2
  71. public    show_cont3, showtime_exit, conv, convloop, conv_cont1, conv_exit
  72. public    showword, showbyte, shownib, show_c1, display_al, click, veryend
  73. public    checkrow_ret, checkrow_exit_reshow
  74.  
  75. public    intvector, counter1, convtable, hours, mins, secs, count, message
  76. public    counter1, counter2, screen_page, attribute, flag
  77.  
  78.  
  79. ;------------------------------  SEGMENT  ---------------------------------
  80.  
  81. code    segment                    ; It must orginate at 0100h
  82.     assume    ds:code, cs:code, es:code    ; or else it can't be a .COM
  83.     org    0100h                ; file and mem-resident.
  84.  
  85. ;-------------------------------  START  ----------------------------------
  86.  
  87. start:                ; make sure DS=CS and jump around data
  88.     push    cs
  89.     pop    ds
  90.     jmp    begin
  91.  
  92. ;-------------------------------  DATA  -----------------------------------
  93. ;
  94. ;  Be sure to use the  CS:  override for all the data in this program
  95. ;  since this is a memory resident routine, and we can't be sure of the 
  96. ;  state of the [ds] register.
  97.  
  98.  
  99. intvector dw    0    ; This defines two words (a doubleword) to hold
  100.       dw    0    ; the address of the old timer routine.
  101. counter1  dw    0         ; A counter for determining when check bottom line
  102. counter2  dw    0    ; Another counter for determining when to display
  103. attribute db    0    ; Stores the screen attribute of the lower line
  104. screen_page  db    0    ; stores the screen page being viewed
  105. mode    db    0    ; stores the screen mode we are in
  106. flag    db    0    ; indicates a redisplay is neccessary
  107. card    db    0    ; =0 if CGA, =1 if Mono, =2 if Compaq graphics card
  108. hours    db    00    ; stores the hours
  109. mins    db    00    ; stores the minutes
  110. secs    db    00    ; stores the seconds
  111. count    dw    0000    ; stores the count of seconds since midnight
  112.     dw    0000
  113.  
  114. message    db    cr,lf,cr,lf,cr,lf
  115.     db    '                    26TIME Version 2.0    3-DEC-86',cr,lf,cr,lf
  116.     db    ' This program was written in MASM 4.0 by Peter Nelson.  It is a memory',cr,lf
  117.     db    ' resident program that occupies 1.8 k-bytes (1856) of ram.  The current time',cr,lf
  118.     db    ' will be displayed on the 26th line of the screen at all times.  It will not',cr,lf
  119.     db    ' interfere with graphing.  It will work with the IBM-CGA, the IBM Mono card',cr,lf
  120.     db    ' the Hercules graphics card, and Compaqs.  Mono & Herc cards will display',cr,lf
  121.     db    ' garbage on the right half of the lower line.  ENJOY!',cr,lf,cr,lf,'$'
  122.  
  123. convtable db    01h,02h,04h,08h,016h,032h,064h   ; used for bin-dec convert
  124.  
  125.  
  126.  
  127. ;------------------------------  PROGRAM  ---------------------------------
  128.  
  129. begin:
  130.     mov    ah, 9            ; display logo
  131.     mov    dx, offset message
  132.     int    msdos
  133.  
  134. whatcard:                ; figure out what graphics card used
  135.     mov    cs:card, 0        ; the default adapter is the CGA
  136.  
  137.     mov    cx, bios_data_seg    ; segment of bios data bytes
  138.     mov    es, cx
  139.     mov    al, byte ptr es:equip_flag  ; get the first byte of the
  140.     and    al, 00110000b        ; equip list, and isolate the crt
  141.     cmp    al, 00110000b        ; switches.  If they are set so, then
  142.     ifr e    <mov cs:card, 1>    ; we are using a monographics card.
  143.  
  144.     mov    cx, compaq_seg        ; if this memory location holds
  145.     mov    es, cx            ; 'CO' then this is a compaq
  146.     cmp    word ptr es:compaq_off, compaq_co  ; computer
  147.     ifr e    <mov cs:card, 2>
  148.     
  149. setvectors:
  150.     mov    ah, 035h    ; use DOS interrupt function 35h to find the
  151.     mov    al, 01Ch    ; current location of the timer interrupt
  152.     int    msdos        ; routine.  Save that location in 
  153.     mov    intvector, bx    ; [intvector].
  154.     mov    intvector+2, es
  155.  
  156.     push    cs                ; Point the timer interrupt
  157.     pop    ds                ; to my program using DOS
  158.     mov    dx, offset int18_routine    ; interrupt function 25h
  159.     mov    ah, 025h
  160.     mov    al, 01Ch
  161.     int    msdos
  162.  
  163.     mov    dx, offset veryend        ; terminate and stay in
  164.     int    terminate_stay_resident        ; memory using DOS int. 27h
  165.  
  166.  
  167.  
  168. ;------------------------------  ROUTINES  --------------------------------
  169.  
  170. int18_routine:            ; this routine is called 18.2 times/second
  171.     pushall            ; Save all the registers and the flags.
  172.  
  173.     inc    cs:counter2        ; this counter is used to 
  174.     cmp    cs:counter2, 1092    ; display time once/minute
  175.  
  176. ;**  uncomment this and comment above line to display seconds
  177. ;    cmp    cs:counter2, 18        ; display time once/second
  178. ;**
  179.     jb    int18_cont1
  180.     mov    cs:counter2, 0
  181.     call    showtime
  182.  
  183. int18_cont1:
  184.     inc    cs:counter1        ; this counter is used to check
  185.     cmp    cs:counter1, 9        ; the row color twice/second
  186.     jb    exit
  187.     mov    cs:counter1, 0
  188.     call    checkrow
  189.     cmp    cs:flag, 0
  190.     je    exit
  191.     mov    cs:counter2, 1091    ; make time display next timer tick
  192.  
  193. exit:
  194.     popall                ; restore all the registers and flags
  195.  
  196.     jmp    dword ptr cs:[intvector]    ; branch to the original
  197.                         ; timer interrupt routine
  198.  
  199. ;--------------------------------------------------------------------------
  200.  
  201. checkrow:                ; this routine is called twice/second
  202.     mov    ah, 0Fh            ; see what video mode we are in
  203.      int    screen
  204.     cmp    al, 7
  205.     je    check_cont0a        ; mode = 7 if hercules card
  206.     cmp    al, 3
  207.     ifr a    <jmp checkrow_ret>      ; mode = 3-6 if in graphics mode
  208. check_cont0a:
  209.     cmp    cs:mode, al        ; see if the mode changed
  210.     je    short check_cont0
  211.     mov    cs:attribute, 0        ; and make it redraw if changed    
  212.     mov    cs:mode, al        ; by making the color-check part fail
  213.  
  214. check_cont0:
  215.     mov    ah, 0Fh        ; save the cursor in the [si] reg
  216.     int    screen
  217.     mov    bl, al        ; save the mode in [bl]
  218.     mov    ah, 3
  219.     int    screen
  220.     mov        si, dx
  221.  
  222.     cmp    cs:screen_page, bh    ; if the page being viewed changes,
  223.     je    check_cont1        ; be sure to keep up with it.
  224.     mov    cs:screen_page, bh    ; change the attribute to 0
  225.     mov    cs:attribute, 0        ; so the time will be redrawn
  226.  
  227. check_cont1:
  228.     mov    di, 0        ; to indicate 80 column mode, [di]=0
  229.     cmp    bl, 2
  230.     ifr b    <mov di, 1>    ; to indicate 40 column mode, [di]=1
  231.  
  232.     mov    ah, 2        ; put the cursor at the end of the 26th
  233.     mov    dh, 25        ; line and see if there is an 'm' there.
  234.     mov    dl, 78        ; if not, then something must have 
  235.     cmp    di, 1        ; erased the screen.  set cs:attribute
  236.     ifr e    <mov dl, 38>    ; to 0 so the next little bit will catch it
  237.     cmp    cs:card, 1    ; and redraw the bottom line.  Make sure if
  238.     ifr e    <mov dl, 7>    ; we are using a herc card that we check
  239.     int    screen        ; positions 6 and 7 too.
  240.     mov    ah, 8
  241.     int    screen
  242.     cmp    cs:card, 1    ; if not using a herc, check 'al' and see
  243.     jne    check_cont1a    ; if it equals 'm'
  244.     cmp    al, 'm'        ; if so, the check anyways and jump if it
  245.     je    check_cont1a    ; is equal 'm'.  If not, check position
  246.     mov    dl, 6        ; 6 on the screen.
  247.     mov    ah, 2
  248.     mov    dh, 25
  249.     int    screen
  250.     mov    ah, 8
  251.     int    screen
  252. check_cont1a:
  253.     cmp    al, 'm'
  254.     ifr ne    <mov cs:attribute, 0>
  255.  
  256.     mov    ah, 2        ; set cursor to y=24, x=end-of-row
  257.     mov    dh, 24
  258. ;    mov    dl, 0        ; uncomment this and comment-out the next
  259.     mov    dl, 79        ; three lines if you want x=start-of-row
  260.     cmp    di, 1
  261.     ifr e    <mov dl, 39>
  262.     int    screen
  263.     mov    ah, 8        ; read the color there
  264.     int    screen
  265.     cmp    cs:attribute, ah  ; leave now if its the same
  266.     je    checkrow_exit_fine
  267.     mov    cs:attribute, ah  ; else save the new color and change screen
  268.     mov    bl, ah        ; save the color in [bl]
  269.     mov    ah, 2        ; set the cursor to the 26th line, 1st pos.
  270.     mov    dh, 25
  271.     mov    dl, 0
  272.     int    screen
  273.     mov    al, ' '        ; and print spaces across the 26th row
  274.     mov    cx, 80
  275.     cmp    di, 1
  276.     ifr e    <mov cx, 40>
  277.     mov    ah, 9
  278.     int    screen
  279.  
  280. checkrow_exit_reshow:
  281.     mov    cs:flag, 1
  282.     jmp    short checkrow_exit
  283.  
  284. checkrow_exit_fine:
  285.     mov    cs:flag, 0
  286.  
  287. checkrow_exit:
  288.     mov    ah, 0Fh        ; restore the cursor position
  289.     int    screen
  290.     mov    ah, 02
  291.     mov    dx, si        ; get position from [si]
  292.     int    screen    
  293.  
  294. checkrow_ret:
  295.     ret
  296.  
  297. ;--------------------------------------------------------------------------
  298.  
  299. showtime:            ; this is called once/minute, and when
  300.                 ; the screen color changes.
  301.     mov    ah, 0Fh        ; see what video mode we are in
  302.     int    screen
  303.     cmp    al, 7        ; mode=7 if hercules card.
  304.     je    showtime_cont
  305.     cmp    al, 3
  306.     ifr a    <jmp showtime_exit>  ; and don't print if in graphics mode
  307. showtime_cont:
  308.     call    click        ; make a nice 'tick' sound
  309.     
  310.     mov    ah, 0
  311.     int    time_of_day
  312.  
  313.     mov    ax, dx        ; divide ticks by 91
  314.     mov    dx, cx
  315.     mov    bx, 91
  316.     div    bx
  317.  
  318.     mov    cx, dx        ; and save the remainder in [cx]
  319.  
  320.     mov    bx, 5        ; multiply result by 5
  321.     mul    bx
  322.     mov    cs:count, ax
  323.     mov    cs:count+2, dx    ; save the result in [count]
  324.  
  325.     mov    ax, cx        ; divide the remainder (saved in [cx])
  326.     mov    dx, 0        ; by 18.  This is the same as dividing by
  327.     mov    bx, 18        ; 18.2.  I can't divide by 18 first because
  328.     div    bx        ; at midnight this would give me a result
  329.                 ; greater than 0FFFFh.  The margin of error
  330.                 ; is small.  32 seconds at midnight, less
  331.                 ; earlier in the day.
  332.  
  333.     add    ax, cs:count    ; add the result into [count] then save.
  334.     mov    cs:count, ax    ; [count] now holds the total number of     
  335.                 ; elapsed seconds since midnight (DOS).
  336.  
  337.     mov    ax, cs:count    ; divide the secs-since-midnight by 3600
  338.     mov    dx, cs:count+2    ; to get the hours since the start of the day
  339.     mov    bx, 3600
  340.     div    bx             ; hours are now in [AL].  remainder
  341.     mov    cs:hours, al     ; is in [DL]
  342.  
  343.     mov    ax, dx        ; divide the remainder by 60 to get the
  344.     mov    bl, 60        ; minutes since the start of the hour
  345.     div    bl
  346.     mov    cs:mins, al      ; is in [AH]
  347.  
  348.     mov    cs:secs, ah      ; seconds are the remainder from above.
  349.                 ; [hours] now has the current hour in
  350.                 ; military format. [mins] has the current
  351.                 ; minutes.  [secs] the current seconds.
  352.  
  353.  
  354.  
  355.     mov    ah, 0Fh        ; get current screen info
  356.     int    screen
  357.     mov    bl, al        ; save the mode in [bl]
  358.     mov    ah, 3
  359.     int    screen        
  360.     mov        si, dx        ; save the cursor position in [si]
  361.  
  362.     mov    dl, 71        ; set up x-pos to print time at.  40cols=32
  363.     cmp    bl, 2        ; 80cols=72.
  364.     ifr b    <mov dl, 31> 
  365. ;**   uncomment this and comment above 3 lines if you want to display seconds    
  366. ;    mov    dl, 68        ; set up x-pos to print time at.  40cols=32
  367. ;    cmp    bl, 2        ; 80cols=72.
  368. ;    ifr b    <mov dl, 28> 
  369. ;**
  370.     cmp    cs:card, 1    ; if this is a hercules card the print at
  371.     ifr e    <mov dl, 0>    ; beginning of the line, instead of end
  372.  
  373.     mov    bh, cs:screen_page  ; set cursor position, y=26, x=[dl] reg.
  374.     mov    ah, 2
  375.     mov    dh, 25
  376.     int    screen
  377.  
  378.     cmp    cs:card, 0    ; find out which graphics card is active,
  379.     ifr e    <call setcga>    ; and call the appropriate routine to set
  380.     cmp    cs:card, 1    ; the card to 26 lines.  I must do this
  381.     ifr e    <call setmono>    ; each time I display the time cuz some
  382.     cmp    cs:card, 2    ; program (lotus) incessantly reset it.
  383.     ifr e    <call setcompaq>  
  384.  
  385.     mov    al, cs:hours    ; show the time in standard format (AM/PM)
  386.     mov    di, 'a'        ; set the [di] reg to 'a'
  387.     cmp    al, 24
  388.     jne    show_cont0a
  389.     mov    al, 0          ; take care of the 32 second error in my
  390.     mov    cs:secs, 0    ; so it is 12:00:00 midnight for 32 seconds
  391. show_cont0a:
  392.     cmp    al, 12
  393.     ifr ae    <mov di, 'p'>    ; if hours >= 12 then it is 'pm', not 'am'.
  394.     jbe    show_cont1    ; here we convert from military to standard.
  395.     sub    al, 12        ; subtract 12 from hours.
  396. show_cont1:
  397.     cmp    al, 0        ; if hours=0 then it's midnight
  398.     jne    show_cont1a
  399.     mov    al, 12
  400.     mov    di, 'a'        ; and it is 'am', at midnight
  401. show_cont1a:
  402.     cmp    al, 10        ; if there is only 1 digit in the hours
  403.     jae    show_cont2    ; (1:00-9:00) then don't print a leading
  404.     mov    ah, al        ; zero, so we have to call shownib instead
  405.     mov    al, ' '        ; of show byte.
  406.     cmp    cs:card, 1    ; if this is a hercules card then we are
  407.     ifr ne    <call display_al>  ; printing at start of line, so don't
  408.     mov    al, ah        ; a leading space.
  409.     call    conv
  410.     call    shownib
  411.     jmp    short show_cont3
  412. show_cont2:
  413.     call    conv        ; here the hours are between 10:00 and 12:00
  414.     call    showbyte    ; so print the whole byte.
  415. show_cont3:
  416.     mov    al, ':'        ; display a colon
  417.     call    display_al
  418.     mov    al, cs:mins    ; display the minutes, leading zeros are
  419.     call    conv        ; neccessary.
  420.     call    showbyte
  421.  
  422. ;**  uncomment this to display seconds
  423. ;    mov    al, ':'        ; un-comment this to display the seconds.
  424. ;    call    display_al    ; you must also then change the position
  425. ;    mov    al, cs:secs    ; where the time is printed on the line, and
  426. ;    call    conv        ; must change the cs:counter2 check so the
  427. ;    call    showbyte    ; routine is called more frequently.
  428. ;**
  429.     mov    al, ' '
  430.     call    display_al    ; here we display either ' am' or ' pm'
  431.     mov    ax, di
  432.     call    display_al
  433.     mov    al, 'm'
  434.     call    display_al
  435.  
  436.     mov    ah, 0Fh        ; restore the cursor position
  437.     int    screen
  438.     mov    ah, 02
  439.     mov    dx, si        ; get position from [si]
  440.     int    screen    
  441.  
  442. showtime_exit:
  443.     ret
  444.  
  445. ;--------------------------------------------------------------------------
  446.  
  447. setmono:
  448.     mov    dx, 03B4h    ; I could make this a little table or
  449.     mov    al, 4        ; something, but it would take more 
  450.     out     dx, al        ; processing time, and I want this to run
  451.     inc    dx        ; as fast as possible.  Here I move the
  452.     mov    al, 26        ; value 26 into register 4 of the graphics
  453.     out    dx, al        ; chip.
  454.  
  455.     dec    dx        ; register 5, value 3
  456.     mov    al, 5
  457.     out    dx, al
  458.     inc    dx
  459.     mov    al, 3
  460.     out    dx, al
  461.  
  462.     dec    dx            ; register 6, value 26
  463.     mov    al, 6
  464.     out    dx, al
  465.     inc    dx
  466.     mov    al, 26
  467.     out    dx, al
  468.  
  469.     dec    dx        ; register 7, value 26
  470.     mov    al, 7
  471.     out    dx, al
  472.     inc    dx
  473.     mov    al, 26
  474.     out    dx, al
  475.  
  476. setmono_exit:
  477.     ret
  478.  
  479. ;--------------------------------------------------------------------------
  480.  
  481. setcompaq:             ; Note that the output port is different
  482.     mov    dx, 03D4h    ; than the mono graphics adapter routine's,
  483.     mov    al, 4        ; but it is otherwise identical.
  484.     out     dx, al        ; register 4, value 26
  485.     inc    dx    
  486.     mov    al, 26
  487.     out    dx, al
  488.  
  489.     dec    dx        ; register 5, value 3
  490.     mov    al, 5
  491.     out    dx, al
  492.     inc    dx
  493.     mov    al, 3
  494.     out    dx, al
  495.  
  496.     dec    dx            ; register 6, value 26
  497.     mov    al, 6
  498.     out    dx, al
  499.     inc    dx
  500.     mov    al, 26
  501.     out    dx, al
  502.  
  503.     dec    dx        ; register 7, value 26
  504.     mov    al, 7
  505.     out    dx, al
  506.     inc    dx
  507.     mov    al, 26
  508.     out    dx, al
  509.  
  510. setcompaq_exit:
  511.     ret:
  512.  
  513. ;--------------------------------------------------------------------------
  514.  
  515. setcga:        
  516.     mov    dx, 03d4h    ; make the screen 26 lines long
  517.     mov    al, 6        ; this is done by setting register #6 of the
  518.     out    dx, al        ; CGA card to 26.  It is possible to get
  519.     mov    dx, 03d5h    ; as many as 29 rows of text with a CGA.
  520.     mov    al, 26
  521.     out    dx, al
  522. setcga_exit:
  523.     ret
  524.     
  525. ;--------------------------------------------------------------------------
  526.  
  527. conv:                ; in: [al] contains the number to convert.
  528.     push    bp        ; it must be less than 063h hex.  out:
  529.     push    cx        ; [al] is now converted.  [ah] is destroyed
  530.  
  531.     mov    bp, 0        ; use the DAA operand to add up the value of
  532.     mov    ah, al        ; the lower 7 bits of [al] and save the
  533.     mov    al, 0        ; result in [al].  Refer to [convtable].
  534.     mov    cx, 7
  535. convloop:
  536.     shr    ah, 1
  537.     jnc     conv_cont1   
  538.     mov    bl, cs:[bp+convtable]
  539.     add    al, bl
  540.     daa
  541. conv_cont1:
  542.     inc    bp
  543.     loop    convloop
  544.  
  545. conv_exit:
  546.     mov    ah, al
  547.     pop    cx
  548.     pop    bp
  549.     ret
  550.  
  551. ;--------------------------------------------------------------------------
  552.  
  553.  
  554. showword:            ;This routine displays a word (AX)
  555.     push    ax
  556.     push    cx
  557.     mov     cl,8
  558.     shr    ax,cl
  559.     call    showbyte
  560.     pop    cx
  561.     pop    ax
  562.  
  563. showbyte:            ;This routine displays a byte (AL)
  564.     push    ax
  565.     push    cx
  566.     mov     cl,4
  567.     shr    al,cl
  568.     call    shownib
  569.     pop    cx
  570.     pop    ax
  571.     
  572. shownib:            ;This routine displays lower nibble(AL)
  573.     push    ax
  574.     push    dx
  575.  
  576.     and     al, 0Fh
  577.     mov     dl,'0'
  578.      cmp     al,0Ah        ;Hm.. need higher OR value? for hex digit
  579.     jl    show_c1
  580.     mov     dl,('A'-10)
  581.  
  582. show_c1:
  583.     add    dl,al
  584.     mov    al, dl
  585.     call    display_al
  586.     pop    dx
  587.     pop    ax
  588.     ret
  589.  
  590. display_al:
  591.     push    ax            ;This routines displays an ascii byte (AL)
  592.     push    bx
  593.     push    bp
  594.     pushf
  595.  
  596.     push    ax
  597.     mov    ah, 0Fh
  598.     int    screen
  599.     mov    ah, 08h
  600.     int    screen
  601.     mov    bl, al
  602.     pop    ax
  603.     mov    ah, 0Eh
  604.     int    screen
  605.  
  606.     popf
  607.     pop    bp
  608.     pop    bx
  609.     pop    ax
  610.     ret
  611.  
  612. ;--------------------------------------------------------------------------
  613.  
  614. click:            ; IN=none, OUT=none, all regs preserved.
  615.     push    ax
  616.     push    cx
  617.  
  618.     mov    al, 10110110b
  619.     out    timer+3, al
  620.     mov    ax, 0777h     ; this is the frequency of the tone
  621.     out    timer+2, al
  622.     mov    al, ah
  623.     out    timer+2, al
  624.     in    al, port_b
  625.     mov    ah, al
  626.     or    al, 03h
  627.     out    port_b, al
  628.     mov    cx, 0018h     ; this is the duration of the tone
  629.     loop    $
  630.     mov    al, ah
  631.     out    port_b, al
  632.     
  633.     pop    cx
  634.     pop    ax
  635.     ret    
  636.  
  637.  
  638. ;--------------------------------  ENDS  ----------------------------------
  639.  
  640.          db    0        ; this is here for the DOS terminate-and-
  641. veryend:            ; stay-resident function to work properly.
  642. code    ends
  643.     end    start
  644. ;------------------------------  ROUTINES  --------------------------------
  645.